/*
 * utils.c
 *
 *  Created on: Apr 5, 2010
 *      Author: nguyencao
 */

#include "utils.h"

#define 	MPDIM2 		80
#define 	MPCDIM2 		400

void init(INTEGER i) {
	mpz_init(i);
}

// init an integer and assign an integer value
void init2(INTEGER i, int v) {
	mpz_init(i);
	mpz_set_si(i, v);
}

// ADD:  C = A + B
void add(INTEGER a, INTEGER b, INTEGER c) {
	mpz_add(c, a, b);
}

// ADD:  C = A + B
void add2(INTEGER a, int b, INTEGER c) {
	INTEGER b2;
	init2(b2,b);
	mpz_add(c, a, b2);
	clear(b2);
}

// a = b
void set(INTEGER a, INTEGER b) {
	mpz_set(a, b);
}

// a = b
void set2(INTEGER a, int b) {
	INTEGER b2;
	init2(b2,b);
	mpz_set(a, b2);
	clear(b2);
}

void set3(int* a, INTEGER b){
	*a = mpz_get_si(b);
}

void clear(INTEGER c) {
	mpz_clear(c);
}

// SUB: C = A - B
void sub(INTEGER a, INTEGER b, INTEGER c) {
	mpz_sub(c, a, b);
}

// SUB: C = A - B
void sub2(INTEGER a, int b, INTEGER c) {
	INTEGER b2;
	init2(b2,b);
	mpz_sub(c, a, b2);
	clear(b2);
}
// a = b (mod c)
// Set a to b mod c. The sign of the divisor is ignored; the result is always non-negative
void mod(INTEGER a, INTEGER b, INTEGER c) {
	mpz_mod(a, b, c);
}

// a = b (mod c)
// Set a to b mod c. The sign of the divisor is ignored; the result is always non-negative
int mod2(INTEGER a, int b) {
	INTEGER b2;
	INTEGER c2;
	int c;

	init(c2);
	init2(b2,b);
	mpz_mod(c2, a, b2);
	set3(&c, c2);
	clear(b2);
	clear(c2);

	return c;
}

// C = A*B
void mul(INTEGER a, INTEGER b, INTEGER c) {
	mpz_mul(c, a, b);
}

// C = A*B
void mul2(INTEGER a, int b, INTEGER c) {
	mpz_mul_si(c, a, b);
}

// C = A/B
void div3(INTEGER a, INTEGER b, INTEGER c, INTEGER d) {
	mpz_fdiv_q(c,a,b);
	mpz_fdiv_r(d, a, b);
}

// C = A/B
void div2(INTEGER a, int b, INTEGER c) {
	INTEGER b2;
	init2(b2,b);
	mpz_fdiv_q(c,a,b2);
	clear(b2);
}

// A = B*q + r
void div_qr(INTEGER a, int b, INTEGER q, int *r) {
	mpz_cdiv_q_ui(q, a, (unsigned long int)b);
	INTEGER r2;
	init(r2);
	mpz_fdiv_r_ui(r2, a, (unsigned long int)b);
	*r = (int)mpz_get_ui(r2);
	clear(r2);
}

// a = b
void mcopy(INTEGER a, INTEGER b) {
	mpz_set(a, b);
}
// c = b^n
void mpow(int b, int n, INTEGER c) {
	mpz_ui_pow_ui(c, (unsigned long int)b, (unsigned long int)n);
}

// if a > b return 1 , else if a = b return 0, else -1
int compare(INTEGER a, INTEGER b) {
	return mpz_cmp(a, b);
}

// if a > b return 1 , else if a = b return 0, else -1
int compare2(INTEGER a, int b) {
	INTEGER b2;
	init2(b2,b);
	int result = mpz_cmp(a, b2);
	clear(b2);
	return result;
}

// c = a & b
void bitwiseAND(INTEGER a, INTEGER b, INTEGER c) {
	mpz_and(c, a, b);
}

// c = a & b
void bitwiseAND2(INTEGER a, int b, INTEGER c) {
	INTEGER b2;
	init2(b2,b);
	mpz_and(c, a, b2);
	clear(b2);
}

void bitwiseOR(INTEGER c, INTEGER a, INTEGER b) {
	mpz_ior(c, a, b);
}

void bitwiseXOR(INTEGER c, INTEGER a, INTEGER b) {
	mpz_xor(c, a, b);
}

// c = abs(b)
void abs2(INTEGER c, INTEGER b) {
	mpz_abs(c, b);
}

// c = -b
void negative(INTEGER c, INTEGER b) {
	mpz_neg(c, b);
}

void gcd(INTEGER c, INTEGER a, INTEGER b){
	mpz_gcd (c, a, b);
}

int gcd1(int u, int v) {
	INTEGER u1;
	init2(u1,u);
	INTEGER v1;
	init2(v1,v);
	INTEGER g1;
	init(g1);
	gcd(g1,u1,v1);
	int g = mpz_get_ui(g1);
	clear(u1);
	clear(v1);
	clear(g1);
	return g;
}

// Return the number of digits of the large integer a
int size2(INTEGER a) {
	return (int)mpz_sizeinbase(a,10);
}

// We need a function to break the large integer a into subgroup of maximum size is 10
